from typing import Optional

from .base import FunctionTypeLogging
from ..core.meta import AliasError


class property_desc(FunctionTypeLogging):
    func_type = property

    def __init__(
            self,
            message: Optional[str] = None,
            alias: Optional[str] = None,
            logging: Optional[bool] = True,
            allure_step: Optional[bool] = True
    ):
        self.property = None
        self.func_get_message: Optional[str] = message
        self.func_set_message: Optional[str] = None
        self.func_del_message: Optional[str] = None

        super().__init__(alias=alias, logging=logging, allure_step=allure_step)

    def __get__(self, instance, owner):
        self.execute_func = lambda: self.property.__get__(instance, owner)
        # 对象调用才会解析日志
        if instance:
            return self.run(self.func_get_message, self.property.fget, instance)
        else:
            return self

    def __set__(self, instance, value):
        self.execute_func = lambda: self.property.__set__(instance, value)
        if instance:
            return self.run(self.func_set_message, self.property.fset, instance, value)
        else:
            return self

    def __delete__(self, instance):
        self.execute_func = lambda: self.property.__delete__(instance)
        if instance:
            return self.run(self.func_del_message, self.property.fdel, instance)
        else:
            return self

    @classmethod
    def setter_desc(
            cls,
            message: Optional[str] = None,
            alias: Optional[str] = None,
            logging: Optional[bool] = True,
            allure_step: Optional[bool] = False
    ):  # 装饰 property.setter
        obj = cls(
            logging=logging,
            allure_step=allure_step,
        )
        obj.func_set_message = message
        obj.alias = alias
        return obj

    @classmethod
    def deleter_desc(
            cls,
            message: Optional[str] = None,
            alias: Optional[str] = None,
            logging: Optional[bool] = True,
            allure_step: Optional[bool] = False
    ):  # 装饰 property.deleter
        obj = cls(logging=logging, allure_step=allure_step)
        obj.func_del_message = message
        obj.alias = alias
        return obj

    def setter(self, func):
        self.property = self.property.setter(func)
        return self

    def deleter(self, func):
        self.property = self.property.deleter(func)
        return self

    def __call__(self, property_obj):
        # 如果是一个 property 对象，那么只能装饰 @property 或者 @property.setter 或者 @property.deleter 其中之一
        if isinstance(property_obj, property):
            self.property = property_obj
            return self
        # 如果是一个 type(self) 对象
        elif isinstance(property_obj, type(self)):
            if self.func_set_message:
                property_obj.func_set_message = self.func_set_message
            if self.func_del_message:
                property_obj.func_del_message = self.func_del_message
            if self.alias:
                if property_obj.alias:
                    raise AliasError(f"alias已经设置为 {self.alias}")
                property_obj.alias = self.alias

            return property_obj
        else:
            raise TypeError(f"{property_obj}必须是一个property对象")
